#!/usr/bin/env python
# Caracas 16/10/2012
#
# Implementacion de la Gramatica y TAD de
# la tabla de simbolos 
#
# Integrantes:
#	Krysler Pinto 09-10661
#	Carlos Aponte 09-10041
# 

import LexerGisela # importamos lexer
import yacc
import sys
import SymTable
import Caja
global TS
tokens = LexerGisela.tokens #Los tokens que genera el lexer

# Clase que representa un programa gisela
class PROGRAMA:
    def __init__(self,proc,decl,sec):
        self.listProc = proc			# Lista de procedimientos
        self.listDecl = decl			# Lista de declaraciones
        self.sec = sec					# Secuenciacion
        self.nombre ="PROGRAMA"
                
class PROCEDIMIENTO:
    def __init__(self,nombre,ldecl,cuerpo)
        self.listDecl = ldecl
        self.nombre = nombre
        self.cuerpo = cuerpo
        tabla = SymTable.SymTable('Tabla de Simbolos Procedimiento')	# Declaracion de la tabla de simbolos
	Symtable.tabla.setPadre(TS)		#Su padre va a ser la tabla de simbolos principal
        lDecl = self.listDecl
        for tupla in lDecl:
            for lVar in tupla[0]:
                if not Symtable.tabla.isMember(lVar):
                    # tabla.agregar (variable,(valor,tipo,modificable) )
                    if(tupla[1]=='char'):
						valor = '!'
					if(tupla[1]=='bool'):
						valor = 'fsalse'
					if(tupla[1]=='int'):
						valor = 0
                    elem = Caja.Caja(lvar,tupla[1],valor)
                    Symtable.tabla.insert(lVar)
                else: print "Hay un error"
		
# Clase que representa la instruccion de entrada estandar read 
class READ:
    def __init__(self,msg,valor):
		self.mensaje= msg
        self.valor = valor
        self.nombre ="READ"

# Clase que representa la instruccion de salida estandar read 
class PRINT:
    def __init__(self,msg,valor):
        self.mensaje= msg
        self.valor = valor
        self.nombre ="PRINT"
        
# Clase que representa la instruccion de repeticion 
class REPETICION:
    def __init__(self,guardia,cuerpo,ramaelse):
        self.guardia=guardia
        self.cuerpo=cuerpo
        self.ramaelse=ramaelse
        

# Clase que representa la instruccion de secuenciacion
class SECUENCIACION:
    def __init__(self,elem1,elem2):
        self.elem1= elem1
        self.elem2 = elem2
        self.nombre ="SECUENCIACION"

# Clase que representa la instruccion condicional
class CONDICIONAL:
    def __init__(self,guardia,exito,ramaelse):
        self.guardia=guardia
        self.exito=exito
        self.ramaelse=ramaelse
        self.nombre ="CONDICIONAL" 

# Clase que representa la instruccion de asignacion
class ASIGNACION:
    def __init__(self,var,val):
        self.val=val
        self.var=var
        self.nombre = "ASIGNACION"
        
# Clase que representa la instruccion de declaracion
class DECLARACION:
    def __init__(self,tipo,variable):
        self.tipo=tipo
        self.variable=variable
        self.nombre = "DECLARACION"    

# Clase que representa TODAS las expresiones binarias 
class EXPREBIN:
    def __init__(self,tipo, operador, subI, subD):
        self.subI = subI
        self.subD = subD
        self.operador = operador
        self.tipo = tipo
        self.nombre = "EXPREBIN"
    def getTipo(self):
        return self.tipo

# Clase que representa TODAS las expresiones unarias 
class UNARIO:
    def __init__(self,nombre,valor, operador):
        self.nombre=nombre
        self.operador=operador
        self.valor=valor
    def getTipo(self):
        return self.nombre

# Clase que representa las expresiones 
# base: literales booleanos,char, enteros y variables
class HOJA:
    def __init__(self,nombre,valor):
        self.valor= valor
        self.nombre = nombre
    def getTipo(self):
        return self.nombre
    def getValor(self):
        return self.valor

# Especificacion de las reglas de precedencia
precedence = (
    ('left', 'TkNegacion'),
    ('left', 'TkConjuncion'),
    ('left', 'TkDisyuncion'),
    ('nonassoc', 'TkXor'),
    ('nonassoc', 'TkMenor', 'TkMenorIgual', 'TkMayor', 'TkMayorIgual','TkIgual', 'TkDesigual'),
    ('left', 'TkMas', 'TkMenos'),
    ('left', 'TkMult'),
    ('right','TkDiv', 'TkMod'),
    ('right', 'TkPotencia'),
    ('right', 'UMINUS')
) 

# PROGRAMA 
def p_programa(p):
  ''' PROGRAMA :   PROGRAMA Lista_Decla
		| PROGRAMA TkComentario
		| PROGRAMA BLOQUE_PRINCIPAL
		| PROGRAMA Lista_Proc 
		| '''
	p[0]=PROGRAMA()
	
def p_lista_proc(p):
	''' Lista_Proc : Lista_Proc PROCEDIMIENTO
					| PROCEDIMIENTO
	'''
	
# Tipos de datos
def p_tipo(p):
	'''TIPO :   TkInt 
	| TkChar 
	| TkBool '''
	p[0]=str(p[1])

# Lista de declaraciones
def p_Lista_Decla(p):
  '''Lista_Decla :   Lista_Decla DECLARACION TkPuntoYComa
		  |  		DECLARACION TkPuntoYComa '''
	 # Es una lista de tuplas (lista var, tipo)
    if len(p) == 3: p[0] = p[1]
    else:           p[0] = p[1] + [(p[2])]
		
# Bloque principal
def p_BLOQUE_PRINCIPAL(p):
  'BLOQUE_PRINCIPAL : TkLets BLOQUE'
  
 # Invocacion de un procedimiento
def p_invocacion_proc(p):
	'INVOCAR_PROC : IDENT TkParAbre Lista_Exp TkParCierra'
	
 
 
# Definicion de un procedimiento
def p_Def_Proc(p):
	'DEF_PROC : TkProc IDENT TkParAbre Lista_Parametros TkParCierra'
 
# Parametro
def p_parametro(p):
  '''PARAMETRO : TIPO IDENT
	      | TkVar TIPO IDENT '''
 
# Lista de parametros de procedimientos
def p_Lista_Parametros(p):
  '''Lista_Parametros : Lista_Parametros TkComa PARAMETRO
		      | PARAMETRO
		      | '''
		      
# Estructura de un procedimiento
def p_PROCEDIMIENTO(p):
  'PROCEDIMIENTO : DEF_PROC Lista_Decla INST '

# Declaracion
def p_declaracion(p):
    'DECLARACION : TIPO Lista_Ident '
    #Lista del tuplas (tipo,identificador)
    p[0] = [(p[3],p[1])]
 
# List de identificadores
def p_lista_ident(p):
    '''Lista_Ident : Lista_Ident TkComa IDENT
		  | IDENT '''
	
		  
# List de Expresiones
def p_lista_exp(p):
    '''Lista_Exp : Lista_Exp TkComa Exp
		  | Exp '''
		  
# Asignacion
def p_Asignacion(p):
    'ASIGNACION : Lista_Ident TkAsignacion Lista_Exp'
	    
# Instrucciones Simples
def p_Instruccion_Simple(p):
  ''' INST_SIMPLE : READ
		  | PRINT
		  | ASIGNACION
		  | TkAbort
		  | TkSkip
		  | TkReturn
		  | INVOCAR_PROC
  '''
  
# Instruccion Bloque
def p_Instruccion_Bloque(p):
  'INST_BLOQUE : TkGo SECUENCIACION TkOg TkPuntoYComa'
  
# Instrucciones
def p_Instruccion(p):
    ''' INST : INST_SIMPLE
	      | INST_BLOQUE 
	      | REPETICION
	      | CONDICIONAL'''
    
# Comandos con guardia 
def p_Com_Guardia(p):
    ''' Com_Guardia :  Exp TkFlecha INST_SIMPLE
		    | Exp TkFlecha INST_BLOQUE
		    | INST_SIMPLE
		    | INST_BLOQUE''' 
       
# Lista de Comandos con guardia
def p_Lista_Com_Guardia(p):
    ''' Lista_Com_Guardia :  Lista_Com_Guardia TkBarra Com_Guardia
			    | Com_Guardia '''			    
			    
# Condicional
def p_Condicional(p):
   ' CONDICIONAL : TkIf Lista_Com_Guardia TkFi TkPuntoYComa'
			    
# Secuenciacion
def p_Secuenciacion(p):
    ''' SECUENCIACION : SECUENCIACION TkPuntoYComa INST
		       | INST '''
		       
# Bloque
def p_bloque(p):
    'BLOQUE : TkGo SECUENCIACION TkOg TkPuntoYComa'
    
# Ciclos
def p_repeticion(p):
  'REPETICION : TkDo Lista_Com_Guardia TkOd TkPuntoYComa'

# Instruccion para leer un valor de la entrada
def p_read(p):
    ''' READ :    TkRead TkString IDENT
		| TkRead IDENT '''

# Instruccion para escribir en la salida 
def p_print(p):
    ''' PRINT :   TkPrint TkString Exp
		| TkPrint Exp
    '''

# Identificadores de variables
def p_ident(p):
	'''IDENT : TkIdent
		  | TkString_Underscore '''
	p[0]=HOJA('ident',p[1])

# Literales numericos	
def p_num(p):
	'NUM : TkNum'
	p[0]=HOJA('int',p[1])
    
# Expresiones
def p_Exp(p):
  '''
    Exp :   Exp_Bool
	  | Exp_Aritmetica
	  | IDENT
	  | TkParAbre
	  | TkParCierra
	  | TkOrd IDENT
	  | TkOneString
    ''' 
    
# Expresiones Aritmeticas
def p_Exp_Aritmetica(p):
  """
    Exp_Aritmetica :   Exp_Arit_Binaria
		    |  Exp_Arit_Unaria
		    | NUM      
    """ 
    
# Expresiones aritmeticas binarias    
def p_Exp_Arit_Binaria(p):
    """
    Exp_Arit_Binaria :   Exp TkMas Exp
		      |  Exp TkMenos Exp
		      |  Exp TkMult Exp
		      |  Exp TkPotencia Exp
		      |  Exp TkDiv Exp
		      |  Exp TkMod Exp
    """    
    
# Expresiones aritmeticas unarias    
def p_Exp_Arit_Unaria(p):
    """
    Exp_Arit_Unaria :   TkMenos Exp %prec UMINUS
		      | TkChr Exp
    """    

# Expresiones Booleanas  
def p_Exp_Bool(p):
    """
    Exp_Bool :    Exp_Bool_Binaria
		| Exp_Bool_Unaria
		| Exp_Bin_Relacional
		| BOOL
    """  
def p_BOOL(p):
    """
    BOOL : TkTrue
	  | TkFalse
    """
    p[0]=HOJA('bool',p[1]) 
    
# Expresiones Booleanas Binarias 
def p_Exp_Bool_Binaria(p):
    """
    Exp_Bool_Binaria :    Exp TkConjuncion Exp
			 | Exp TkDisyuncion Exp
			 | Exp TkXor Exp
    """    

# Expresiones Booleanas Unarias
def p_Exp_Bool_Unaria(p):
    """
    Exp_Bool_Unaria :      TkNegacion Exp
			 | TkIsUpper Exp
			 | TkIsAlpha Exp
			 | TkIsDigit Exp
			 | TkIsSpace Exp
    """        
    
# Expresiones Binarias Relacionales  
def p_Exp_Bin_Relacional(p):
    """
    Exp_Bin_Relacional :   Exp TkIgual Exp
			 | Exp TkDesigual Exp
			 | Exp TkMenor Exp
			 | Exp TkMenorIgual Exp
			 | Exp TkMayor Exp
			 | Exp TkMayorIgual Exp
    """
    
# Deteccion de Errores
def p_error(p):
    global error
    error = 1
    if (p!=None): print "Error: sintactico en la fila %d" % p.lineno
    else: print "Error: No cumple con la sintaxis de Gisela"    
    
    
# FIN DE LA GRAMaTICA

# --- Funcion principal ---
def main():
    global error
    global data
    global TS
    TS = SymTable.SymTable('Tabla de Simbolos')	# Declaracion de la tabla de simbolos
    
    error = 0
    result = None
    f = open(sys.argv[1])	# Abrimos el archivo
    data = f.read()		# Leemos el archivo
    if data != "":
        LexerGisela.input(data)
        if not LexerGisela.errores:
            yacc.yacc()
            result = yacc.parse(data)
    return result

# --- Fin de funcion principal ---
if __name__ == '__main__':
    main()